dBASE III notes .001 Thomas A. Wells 146 D Street SE See BBS @ 321-7441 Washington, DC 20003 for other notes. (202)546-3409 I am providing a weekly series of these notes covering my experiences as a dBASEIII programmer. I work as a consultant and presently am spending 40+ hours per week writing programs and managing databases using primarily dBASEIII. This week's experience covers an odd occurrence. While interactively programming along, debugging a command file for displaying numbers of items, their record numbers and certain fields, the computer displayed the error message "File is already open". From my copy of the "PRODUCT USAGE REPORT" from A-T (see below), I found that this message should apply only if I tried to use a command file (.PRG) to call itself, which I wasn't! There followed an hour of trying to decide what was wrong, changing EXIT statement locations in various DO WHILE loops both in the main and sub-programs, and trying to figure out why the call had worked twice immediately before the error message appeared, etc. Finally it was time to call the A-T help line - (213)558-0086 (have your dBASE III serial number handy!). After some "Have you tried..." and "Yes, I have, but what about..." iterations, I was told to boot up the backup copy of the .EXE programs. Since I'm using a PC-XT, I put the disk in drive A, typed A:DBASE and lo! Everything worked! The final fix for the problem was to recopy the .EXE programs back to the hard disk from the original system disk with COPY *.EXE C:. Why did this work? I'm not sure, but it appears that the copy of the programs on the hard disk became corrupted, possibly in the stack management area. So far, after another week's run, no further problems have occurred. I'm not suggesting this as a fix for all programming problems, but if you're sure(?) of everything else, give it a try. The experience leaves me a little less sure of the integrity of either dBASEIII or IBM's hard disk. My backups have been more frequent lately. The PRODUCT USAGE REPORT mentioned above has been very helpful. I was sent it on request through the Technical Assistance phone number listed above. The last 10 pages or so list all the dBASEIII error messages and their meanings - very helpful to the programmer and, of course, left out of the original manual. The first half of the document consists of further tips, elucidations and comments regarding installation, programming usage of the various commands, and sections on the dCONVERT and dFORMAT utilities. I don't know whether the report is to be issued monthly or what - mine is dated October 1, 1984. If you're seriously programming with dBASEIII, get one! As a final thought for this week, using Wordstar with the program has been easy and helpful. Linking the two programs requires nothing more than creating a CONFIG.DB file with the statements WP=WS and TEDIT=WS in it. Be sure and run the Wordstar INSTALL program on the version you want to use before you do, so it will come up running in the non-document mode (menu E, letter C does the trick). - - - - - dBASE III notes .002 When adding records to a file, I sometimes like to stop and press F4, the function key that is programmed as "dir;". This gives a listing of the .DBF files only from within dBASEIII. The first time I did this, the file I just added a record to did not show the additional record! That is, the number of records was 89 prior to adding one and still showed 89 after the DIR command. The answer is relatively simple -- the directory does not appear to be updated as records are added -- a command to close the file seems to be required first, such as CLEAR ALL or CLOSE DATABASES. To see how many records have been added, issue the command CLEAR ALL (or equivalent), then DIR. Of course, there are many other ways to determine how many records a file has while in dBASEIII -- also true of nearly every way of doing almost anything. One could type GO BOTTOM, then ?RECNO(). Or if you had just added a record, ?RECNO() would work with out the GO BOTTOM. This week's puzzler happened while trying to index a .DBF file where the first index key was a string (character) variable, and the second key was a numeric variable. According to the rules, the numeric variable must be converted to a string via the STR() function, since multiple indexing keys must all be strings. So I did the conversion. Right in the INDEX command: INDEX ON string_var + STR(numeric_var) TO indexfile The result was puzzling, to say the least. Examination of the file using the EDIT command showed it to be in ascending order, as advertised, with respect to the string_var, but in descending order with respect to the numeric_var! Not what I wanted at all. The conversion to a string should not have affected order of the sort, since the numeric_var was less than 10 (single digit), and the string representation appeared to have the same number of leading blanks for each number. Also, the ASCII value of "2" is higher than that for "1", so the blanks should not have upset the order. The cure? Change the field definition to "character". Then, the indexing command becomes: INDEX ON string_var1 + string_var2 TO indexfile Examination of the ordering of the file then showed it to be organized in ascending order with respect to both keys. - - - - - dBASEIII notes .003 This week's dBASE III tip is for the CONFIG.DB file with thoughts about making screen displays easier to read and maybe a little fancier with bold, underline and graphics. CONFIG.DB... is a file that dBASEIII looks for after you type "DBASE". It may be used for many different purposes including tieing in a word processor other than the built-in one, setting most of the SET parameters and setting the function keys. Let's see how it is used to set the function keys. First, note that once again the manual (p. 1-126) is incorrect. There, we are told to include statements like: F2 = 'CLEAR;' to set the function keys. Not so! If you try this, an error message will greet you, and the key will not be set. The method used to set the function keys is: F2 = CLEAR; Notice that no quotation marks are used. Although it is not mentioned, there is a limit to the number of characters that a function key can represent. I don't know exactly what it is, but if you try to set one key to: F2 = SET PRINT OFF; SET DEVICE TO SCREEN; you will find that the letters at the end, say, "EEN;", have "wrapped" onto F3. To make the above workable, use the following statement: F2 = SET PRIN OFF;SET DEVI TO SCREE; Note the use of the 4-letter abbreviations for the commands, and that no blank is used after the first ";". Here's an example of a CONFIG.DB file using the above information: WP = WSN TEDIT = WSN F2 = clea all; F3 = modi comm F4 = set prin off;set devi to scre; As described in an earlier note, the first two statements link WORDSTAR (INSTALLed in the non-document mode) to the MEMO field editing and the MODIFY command editing. The last three statements set the function keys as described above. The only invisible trick is that for the F3 key there is a blank after the word "comm " so that all I need to do after pressing the F3 key is to type the name of the command file I wish to edit and press enter. The possibilities for using this feature are limited only by the programmer's imagination. If you use this feature for the final end- user program remember that you're really trying to make life simpler for them. GRAPHICS... are not too hard to do with dBASEIII. It will, however, take some patience and trial-and-error... My system is a PC-XT with the Hercules graphics board and the IBM mono monitor. I say this because the results of the statements outlined below will surely be different if you use other hardware. It all started with a desire to make a full screen look better, and also to make the important items stand out. First, DFORMAT was used to draw nice boxes on the screens where they would help make things clearer. Using DFORMAT, if anyone's interested, could be the subject of some entire later notes - it's truly an arcane challenge! After the boxes were drawn, and the .FMT file was generated, I naturally wanted to change something. Go back to DFORMAT? No way. It might be made to edit an existing file, but I'm over 40 and may not have enough time left to figure out how. So how to make changes to the graphics? All the ASCII equivalent characters from the BASIC manual - that's how! dBASEIII will happily put any character on the screen that is on that list, so there is a copy of it hanging on the wall next to my computer. To put a segment of a vertical double line on the screen, just enter: ? CHR(186) And there it is. Of course, @ SAY may also be used. BOLDFACE and UNDERLINE... are somewhat more involved, but easy once you get the idea. If the SET COLOR command is properly used for your hardware, all kinds of emphasis is possible. For you color monitor users, more experimenting will be needed. The challenge with a color monitor is not to overdo it. Here's the trick. For my hardware (above) typing: SET COLOR TO U1/0,0/7,0 results in everything being underlined. Note that the second parameter 0/7 leaves the @ SAY/GET reversed fields alone. Read the manual to see what is affected by each quantity between the parentheses - it's not ALWAYS wrong. Well there is one thing wrong - or at least it "works funny" for me. The underline is supposed to be turned on by the "U". On my computer, the "1" turns on the underline - the "U" can be omitted. To see how this can be put to use in a command file, here's one way to do it. Build a .MEM file by setting the values of "b", "bu", "u" and "off" as shown: Variable Value u "SET COLOR TO U1/0,0/7,0" off "SET COLOR TO 7/0,0/7,0" bu "SET COLOR TO +1/0,0/7,0" b "SET COLOR TO +7/0,0/7,0" After setting the values shown, type [SAVE TO color] [enter]. Then later in a command file use the RESTORE FROM color statement to activate the variables in memory. Don't forget the ADDITIVE modifier if other variables are active. "off" represents the default settings; I think they're same as when dBASEIII is first started. "u" produces underline, "bu" produces both boldface and underline, and "b" produces boldface - all on the screen of course. Then in a command file, or even from the dot prompt, type [&b] [enter] and everything from then 'til the [&off] occurs will be in boldface. The underline is slightly different. If you type [&u] [enter], every line on the screen will suddenly be underlined! Don't worry - if the command is issued in a printed line somewhere, it'll only underline where you tell it to. - - - - - dBASE III notes .004 December 19, 1984 This week - a newsflash, a correction and a print hint: NEWSFLASH Yesterday an update announcement from A-T arrived. The offer was to upgrade to dBASE III version 1.1! The details are that for $25 you get the "improved" version which will run on the PC-AT as well as the PC & XT, and can be "completely installed on any hard-disk IBM PC/XT, AT or 100% IBM PC compatible system". The brochure is understandably silent as to whether or not any of the bugs found by users and/or mentioned in their "Product Usage Re port" were fixed. My check is in the mail. My reaction to this is that since the program has been on the market less than 6 months, a charge for an update is an insult. Is this tactic of charging for each item separately an imitation of IBM? (If the bugs are reduced, maybe it'll be worth it. How about buyers who get version 1.0 this week? Will they get a "free" upgrade? If you know anyone about to invest in dBASE III, make sure they get the word. Surely all the present store stock hasn't been revised to version 1.1 yet.) CORRECTION Last note said there is no stated limit on the length of the SET FUNCTION command. My face is red - right there on page 4-113 of the manual it says 30 characters. PRINT HINT In formatting printouts to either/both the screen and printer it is useful to be able to embed a number inside text. For example, you may want to print: "There are 12 items in this list." In printing them or using @ SAY, the numbers will be preceded by up to 7 blank spaces. In the above example if we issued these commands: ? "There are" ?? n ?? "items in this list." The result would be: There are 12items in this list. Note that there are 6 blanks in front of the number and none after it. There doesn't appear to be any simple way to eliminate the extra blanks in front of the number. Adding one to the end is simple. If you know how long the number will be, say always 2 digits, the answer is simple. Just convert the number to a string and use the STR() function to print only the rightmost 2 characters. But what if the number of digits varies? Here is one way to handle that problem: ? "There are " ?? STR(n,(LOG(n+.5)/LOG(10)+1)) ?? " items in this list." Since there doesn't seem to be any easy way within dBASE III to tell how many digits a number has, the formula above takes your number, n, and uses the LOG() function to do the job, then the STR() function to print the exact number you wanted. The addition of the .5 to the number n is to overcome any internal inaccuracies in the LOG() function's number representation. The result then is: There are 12 items in this list. - - - - - dBASE III notes .005 January 15, 1984 This note deals with "!", "@" and "?". "!" is a very handy tool for the dBASE III programmer. It runs any system level program for you from within dBASE either from the dot prompt or from within a command file. It can be found in the manual under the equivalent syntax of "RUN". For example, I got tired of typing COPY *.dbf a:, etc. at the end of every session to back up all the files that may have changed, and besides that, the end user won't want to or maybe even won't know how to. So here's a backup routine that will back up all the files, with a built-in safety factor. If the operator puts in the wrong disk, an opportunity is given to swap it through the use of the FILE command. Here it is: *********************** BACKUP.PRG ************************** * Backs up .DBF, .MEM and .NDX files for the operator. * * An "invisible command" accessed by pressing "P" is * * included to back up .PRG and .FMT files. This program * * checks to see whether the proper disk is put in drive A * * and gives a chance to abort before the copying begins. * ************************************************************* CLEAR ALL CLEAR SET TALK OFF @ 10,10 SAY "Insert the backup disk into Drive A." @ 12,10 SAY 'Press "B" to begin, "A" to abort' WAIT SPACE(21) to j j = UPPER(j) * Turn the VERIFY function of DOS ON ! VERIFY ON DO CASE j CASE j = "B" * Check to see if correct backup disk is in drive A: IF FILE ("A:filename.DBF") SET CONSOLE OFF * Copy all the database & related files !COPY *.DBF A: !COPY *.MEM A: !COPY *.NDX A: SET CONSOLE ON ELSE * Argue if the disk isn't recognized... @ 12,10 CLEAR * Turn the bright letters on (see earlier note) &b @ 12,10 SAY 'This disk may not be the correct one!' &off @ 14,10 SAY 'When the correct one is inserted, press "B"' @ 16,10 SAY 'To Abort, press "A"' WAIT SPACE(31) TO b b = UPPER(b) DO CASE b CASE b = "B" SET CONSOLE OFF !COPY *.DBF A: !COPY *.MEM A: !COPY *.NDX A: SET CONSOLE ON CASE b = "A" RETURN ENDCASE b CASE j = "A" RETURN * This choice backs up the program and format files CASE j = "P" .AND. FILE('A:filename.PRG') !COPY *.PRG A: !COPY *.FMT A: ENDCASE j SET TALK ON SET CONSOLE ON !VERIFY OFF RETURN If your program files or database files are changed often, this program saves a lot of work. The other possibilities for using "!" (or "RUN", if you must) are intriguing. How about a communications program or another DOS function or ... ? "@" and "?" can both be used to print reports, among other things. "?" is preceded by a linefeed and a carriage return , while "??" is not. Together these two can be used to print many parts of any report, such as headings. Where formatted fields such as telephone numbers, dates or dollar amounts are to be printed, the PICTURE clause is handy, and "@" is probably easier to use. To have the output of both "?" and "@" routed to the printer, it is probably safer to use: SET PRINT ON SET DEVICE TO PRINT Then anything that either "@ SAY" or "?" does is done by the printer and not the console screen. "@ GET" is ignored. Watch out for putting the "@" commands into a sequence that causes the printer to back up either a line or space(s) on a line. You may get an unwanted EJECT by the printer. Here's an example of the use of a mixture of these commands: * Printer codes bold_on = CHR(27) + CHR(88) + CHR(49) bold_off = CHR(27) + CHR(88) + CHR(48) ? bold_on ?? heading ?? SPACE(20) + DTOC(DATE()) ? ? bold_off @ PROW(),0 SAY id_number PICTURE "@R 99-(999)-99" @ PROW(),PCOL()+2 SAY id_number_2 PICTURE "@R 99/999/A" @ PROW(),PCOL()+2 SAY SUBSTR(var1,1,14) @ PROW(),PCOL()+2 SAY var2 + ". " + var3 @ PROW(),PCOL()+2 SAY SUBSTR(var4,1,1) + ". " + var5 @ PROW(),PCOL() SAY RECNO() ? In the example the variables bold_on and bold_off are printer control codes covered in an earlier note, if memory serves. PROW() keeps the cursor on the same line. PCOL()+n spaces the data to match the heading. Either "?" or "@" could have been used to print var1 - var5 and RECNO(). The final "?" is to move the cursor to the beginning of the next line. Without it, any subsequent output will start at the end of RECNO(). Instead of PCOL() +n, a number may be used to select the starting column for the next item. @ PROW(),100 will place the first character in column 100 (just be sure your printer can accommodate column 100). Place your collection of "?" and "@" statements inside one or more DO WHILE loops and you're set to go. - - - - - dBASE III notes .006 January 24, 1984 Version 1.1 has arrived. Comments this time are about v1.1: Installation, Autostart, dFORMAT/SED, and "Oops". INSTALLATION Installation looks difficult, but is easy. The trick is to follow the directions. The bottom line is that yet another protection scheme is used, this time to allow hard disk users to boot directly from the hard disk without the system disk having to be in drive A:. To unravel the directions, you are apparently allowed one copy on the hard disk per system disk. The intent is that if you want to move the software to another machine you must "uninstall" the copy (put it back onto the system disk), then move the program to your other machine. Ridiculous. Even more ridiculous is A-T's statement that you may want to "uninstall" the program if "your hard disk becomes damaged"! They don't tell how to do this wonderful magic feat. I'm opposed to copy protection. There are already several small programs available for unprotecting dBASE III v1.0; those for v1.1 will be soon. AUTOSTART It is now practical (and legal) to boot your database from the hard disk using a combination of the AUTOEXEC.BAT and CONFIG. DB files. Here's how. The AUTOEXEC.BAT file has as its last two statements: CD\DBMS\DB3 dbase The first statement changes the default directory to the dBASE III directory and the last invokes the program. Since v1.1 requires no boot disk in drive A:, it comes alive and looks for a CONFIG.DB file. Mine ends with: COMMAND = DO mainmenu The result of these two additions to these files means that I can walk up to the computer, flip on the main switch and walk away. In about two minutes (using a 640K XT), the main menu is on the screen waiting for my use without ever pressing a key. See page 1-126 in the manual for a little more about CONFIG.DB and an example of COMMAND. dFORMAT/SED What was dFORMAT in v1.0 is SED in v1.1. The new version looks the same as the old, but it's a different size so maybe some of the bugs have been fixed. I liked dFORMAT so I plan to like SED. It is a good time-saver for creating screens for input and output. You can even use fancy boxes! Try it - the on-line help is good. OOPS After one day with v1.1, a bug appeared. Or maybe I should call it a correction to the bug. With v1.0, printing a date to the screen with @ SAY required a PICTURE clause like "@R 99/99/ 99" to get it to look like a date. On the printer, you didn't need it, which agreed with the manual (see page 4-20). That was one page that never made itself clear to me, except it encouraged me into some trial/error that resulted in my not using any PICTURE clauses with date variables except, as noted above, on the screen. If you happen to have a good explanation of page 4-20, please send it right away. Now v1.1 works the same as the printer. No PICTURE clauses needed on the screen. Is that clear from the documentation? No. Documentation for v1.1? Here's the total: Installation - 5 pages Corrections - 4 pages (scattered items) New pages - 1 SED comments - 4 It might be a good idea to funnel all the new and/or old bugs for dBASE III, particularly v1.1, to one person. The idea is to accumulate them and forward to users groups and A-T. - - - - - dBASE III notes .007 April 4, 1985 Today's a good day for some thoughts about screen and printer graphics. I use Wordstar for all my dBASE III programming. As a result, graphics are fairly simple to do, as I hope you'll see shortly. If you use Sidekick, or the dBASE III editor, or some other word processor the principles may or may not apply. The first problem is to get the graphics characters into the editor; that is, to make them available on the screen. I did it by using dFORMAT, supplied with v1.0. The "new" screen-making tool, SED, supplied with v1.1 will make you work harder for the same result. Or less. The process for getting control of lines and boxes is: 1. Draw a box any way you can in either SED or dFORMAT. (Or any other way - all's fair.) 2. Use SED or dFORMAT to generate the .PRG file. (Or see above parentheses) 3. Import the .PRG file into your word processor. 4. Use your word processor's functions for copying, moving and editing to construct other figures as needed. If you have dFORMAT, you can generate a box completely and import the whole thing into your word processor. If you're "stuck" with SED, it's a little more arcane. Here's a short list of keys and their effect on the screen for those with SED: Key CHR() Key CHR() F1 187 F2 200 F3 189 F4 190 F5 191 F6 192 And so on. Refer to your BASIC manual for the figures represented by the ASCII codes. With SED, if you use the SHIFT, ALT and CONTROL keys with the function keys (and even the backslash key) you can get some of the PC graphics & other special characters, but it's almost too time consuming. Besides, after all that I still wasn't able to make a complete box! The vertical line character managed to escape me completely. So I went back to dFORMAT, got both the single and double line samples, and started from there. As another possibility, I used Wordstar in the non-document mode to write this note, so the example below may be used, if you can ingest it with your dBASE III editor. Here's a sample box: @ 2,0 SAY "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" @ 2,55 SAY "MMMMMMMMMMMMMMMMMMMMMMM;" @ 3,0 SAY ":" @ 3,78 SAY ":" @ 4,0 SAY ":" @ 4,14 SAY "Whatever the TITLE of this here screen is..." @ 4,78 SAY ":" @ 5,0 SAY ":" @ 5,78 SAY ":" @ 6,0 SAY ":" @ 6,78 SAY ":" @ 7,0 SAY ":" @ 7,20 SAY "und so weiter..." @ 7,78 SAY ":" @ 8,0 SAY ':' @ 8,78 SAY ":" @ 9,0 SAY ":" @ 9,55 SAY ':' @ 10,0 SAY ":" @ 10,55 SAY ":" @ 11,0 SAY ":" @ 11,55 SAY ":" @ 12,0 SAY ":" @ 12,55 SAY ":" @ 13,0 SAY ":" @ 13,78 SAY ":" @ 14,0 SAY ":" @ 14,55 SAY ":" @ 15,0 SAY ":" @ 15,78 SAY ":" @ 16,0 SAY ":" @ 16,78 SAY ":" @ 17,0 SAY ":" @ 17,78 SAY ":" @ 18,0 SAY ":" @ 18,78 SAY ":" @ 19,0 SAY ":" @ 19,78 SAY ":" @ 20,0 SAY ":" @ 20,78 SAY ":" @ 21,0 SAY ":" @ 21,78 SAY ":" @ 22,0 SAY ":" @ 22,78 SAY ":" @ 23,0 SAY "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" @ 23,55 SAY "MMMMMMMMMMMMMMMMMMMMMMM<" The above code should, if you insert it in a .PRG or a .FMT file, produce a complete box on your screen or printer consisting of gen - yoo - wine PC graphics characters. If you drag this code (or the whole note) into your word processor, you may see only colons (:), H's (H), M's (M), semicolons (;), I's (I) and a less than sign (<). Don't be fooled; this is the way the graphics are displayed by Wordstar. Don't erase one of the "graphics" colons and then try to replace it with a colon from your keyboard - life don't work that way. The ASCII codes for the "real" colon and the "graphics" colon are quite different. By about 128... If you're still here, and have got this figure or an equivalent one into your word processor, you're ready for step 4. Move, copy and delete until you (think you) have reformed the size and shape of your box to suit your need. Then run (DO) the program. Chase the bugs until you get it right, and spruce up all your screens. As a side note, you can also "DO" a .FMT file! Also note that if you have a PC "compatible" printer, both single and double line graphics will print, though most printers print either as only a single line. - - - - - dBASE III notes .008 April 11, 1985 PEEK... is not documented, but a dBASE programmer can have some fun with it and perhaps learn a little about programming and screen handling in the process. So purists are excused from reading the following example program: ******** PEEK.PRG * Prints the location, value & CHR() where possible * OK up to location 32767 - modify for higher locations CLEAR INPUT "begin at ?" to begin INPUT "how many ?" to num loc = begin r = 4 c = 0 DO WHILE loc < begin + num * trim location number & put in proper location on screen * see earlier note for trim technique involving logs @ r,c*25 SAY STR(loc,(LOG(loc+.5)/LOG(10)+1)) pk = PEEK(loc) * take care of "unprintable" characters IF pk > 31 .AND. pk <255 @ ROW(),COL() SAY " CHR("+STR(pk,3)+ ") = "+CHR(pk) ELSE IF pk <> 0 @ ROW(),COL() SAY " CHR("+STR(pk,3) + ")" ELSE @ ROW(),COL() SAY " CHR( 0)" ENDIF ENDIF loc = loc + 1 * print downward on screen r = r + 1 * don't go off the bottom of the screen IF r > 22 r = 4 c = c + 1 * don't go off the right of the screen IF c > 2 c = 0 WAIT @ 4,0 CLEAR ENDIF ENDIF ENDDO * don't overwrite data on the screen when finished @ 23,0 SAY "" If you trim the above program out of this note and run it, you will see: - a request for the locations you want printed on the screen - a request for the number of locations after the start above - columns of data printed The programming techniques used are: - printing in columns because they're easier to read than rows - showing the ASCII representation where possible - managing to stay on the screen, avoiding errors There are two challenges here I'd like to offer. First, see if you can make the program work above location 32767. Second, with the start given, write a disassembler! At least for the memory locations below 32768; you could use a .dbf to store the op-codes and the associated decimal & hex values. Silly? Maybe not, if you consider it a way to learn. INDEXING... can be very helpful for quick access to data in any order, and is necessary for certain other commands such as SEEK, FIND, SET INDEX and SET RELATION. Once a file is INDEXed, it is important to back up the .ndx file whenever the .dbf file is backed up. If you don't back it up, loss of a disk will mean reconstructing the .ndx file. If you know what the index key fields were either from experience or documentation then rebuilding the index file is only time consuming. If you don't know what the key fields were, your problem could be quite substantial. One way to avoid the problem is to keep track of the .ndx file keys. Here's one way to do it: Back up your .ndx files along with the associated .dbf files. A suggested "easy" way to do this is contained in an earlier note. Then keep printed copies of your file structures handy by issuing the command "LIST STRUCTURE TO PRINT" every time you modify the file's structure. Then after each time you create an index file for the .dbf file, type "USE filename INDEX indexname" then press F6 (DISPLAY STATUS) to show the file in use. Note that the .ndx file's name and key fields are also shown. Do a screen print or "DISPLAY STATUS TO PRINT" and tape the index file info to the printout of the .dbf file structure. This process is actually quite easy. Remember to back up any related .mem and .dbt files along with the above. To quote Macpherson's Law: "Murphy's Law is too optimistic.". - - - - - dBASE III notes .009 April 30, 1985 This week's note concerns the "&" and the "*" & is the dBASE MACRO FUNCTION. It looks like an ampersand (because it is!) and works in ways that new dBASE programmers sometimes have a lot of trouble figuring out. First try the program below. It's short but it illustrates the use of the "&" and also the asterisk or NOTE function: **************** ASTERISK.prg * demonstrates the "&" and the "*" **************** a = "*" ? "a" + "&a" &a ? "This is line 1" a = "" &a ? "This is line 2" If the keyword (NOTE) or the asterisk symbol appears in the first column of a line, dBASE ignores the rest of the line. Same as the REM keyword or the apostrophe does in many versions of BASIC. When you run ASTERISK.prg this is what takes place: 1 - the variable "a" is set equal to an asterisk. 2 - the first print statement prints an "a" and then "the contents of a". If you think of the "&" symbol as "the contents of" it may help you see what is taking place. Therefore, since "the contents of a" is an asterisk, that's what appears on the screen. 3 - in the next line the first expression is &a. Since the & is the "contents of " function, the computer looks for its argument "a", sees it is an asterisk and puts that character first on the line. Seeing an asterisk first on a line causes the computer to see the line as a comment and ignore it! 4 - "a" is "nulled out", that is, "a" is set equal to null - the empty string. 5 - nearly the same line as before except that "a" is no longer an asterisk but a null, so the "?" or print statement is executed. The program's output? Here it is: do asterisk a* This is line 2 . Try the program with other values for a such as *fGHY67 and 1234. Expect and interpret different results and error messages. When you are comfortable with &, use it in other dBASE statements such as: SET FILTER TO fieldname = "&variable" LOCATE FOR fieldname = "&variable" and all those other places that "the contents of" a variable are needed. See notes .003 and .005 for examples of other uses of the & function. - - - - - dBASE III notes .010 May 21, 1985 This week's note concerns DO, IF, SUM and "&" macro substitution. It started innocently with a program as outlined below containing a DO WHILE and an IF statement, like this: * FOO.prg * or how to find a bug in dBASE III v1.1 * Initialize some variables date = CTOD("01/01/01") * these are all date field names f1 = "FIELD1" f2 = "B->FIELD2" . . . f28 = "FIELD28" * open the files SELECT 1 USE FILENO1 SELECT 2 USE FILENO2 * link the two files by record no. since there are many fields SELECT 1 SET RELATION TO RECNO() INTO FILENO2 * cause the problems GO TOP DO WHILE .NOT. EOF() IF &f1>date .AND..NOT.(&f23date .AND..NOT.(&f20FIELD2. In this case, the screen position where the result of the GET should have displayed will be blank. It is easy to think "there wasn't anything in the field in that record, so the blank is OK". The blank is NOT OK - it's an error. Thus you want to develop the habit of (at least mentally) questioning every item that is printed by your code. A blank may or may not really be a blank... RUN TEST DATA... The next important step in debugging is to run some test data. Make sure you know in advance what the output will be. Try to run data at both ends and the middle of your data range. For example, if your program accepts data between $40 and $4 million for a variable value, use both of these and several intermediate ones even if the usage of the extremes is rare. Then check the results by hand. LOGIC ERRORS... may be much easier to spot if you run test data. Wrong answers may show them (or may show errors in your hand calculations) much more efficiently than having your boss question them later at an inopportune moment. Other logic errors may show up in printing. Usually obviously. The sneakier kind are those that may show up in selection logic, for example: COUNT FOR YEAR(FIELD3)>0.AND.FIELD16<56.OR.FIELD2